﻿using System;
using System.Diagnostics.Contracts;
using FlitBit.Core;

namespace FlitBit.Cache
{
	/// <summary>
	///   Cache statistics sample.
	/// </summary>
	[Serializable]
	public struct CacheStats
	{
		static readonly int CHashCodeSeed = typeof(CacheStats).AssemblyQualifiedName.GetHashCode();
		readonly int _attempts;

		readonly int _evictions;
		readonly int _expirations;
		readonly int _hits;
		readonly string _name;
		readonly int _removes;
		readonly int _writes;

		/// <summary>
		///   Creates a new instance.
		/// </summary>
		/// <param name="name"></param>
		/// <param name="attempts"></param>
		/// <param name="expirations"></param>
		/// <param name="evictions"></param>
		/// <param name="hits"></param>
		/// <param name="removes"></param>
		/// <param name="writes"></param>
		public CacheStats(string name, int attempts, int expirations, int evictions,
			int hits, int removes, int writes)
		{
			Contract.Requires<ArgumentNullException>(name != null);
			_name = name;
			_attempts = attempts;
			_expirations = expirations;
			_evictions = evictions;
			_hits = hits;
			_removes = removes;
			_writes = writes;
		}

		/// <summary>
		///   Number of attempts.
		/// </summary>
		public int Attempts { get { return _attempts; } }

		/// <summary>
		///   Number of evictions.
		/// </summary>
		public int Evictions { get { return _evictions; } }

		/// <summary>
		///   Number of expirations.
		/// </summary>
		public int Expirations { get { return _expirations; } }

		/// <summary>
		///   Number of hits.
		/// </summary>
		public int Hits { get { return _hits; } }

		/// <summary>
		///   Determines if the instance is empty.
		/// </summary>
		public bool IsEmpty { get { return _name == null; } }

		/// <summary>
		///   Gets the name of the cache from which the stats were sampled.
		/// </summary>
		public string Name { get { return _name; } }

		/// <summary>
		///   Number of removes.
		/// </summary>
		public int Removes { get { return _removes; } }

		/// <summary>
		///   Number of writes.
		/// </summary>
		public int Writes { get { return _writes; } }

		/// <summary>
		///   Determines if equal to another object.
		/// </summary>
		/// <param name="obj"></param>
		/// <returns></returns>
		public override bool Equals(object obj)
		{
			return obj is CacheStats && Equals((CacheStats) obj);
		}

		/// <summary>
		///   Calculates the instance's hashcode.
		/// </summary>
		/// <returns></returns>
		public override int GetHashCode()
		{
			const int prime = Constants.NotSoRandomPrime;
			var res = CHashCodeSeed * prime;
			if (_name != null)
			{
				res ^= _name.GetHashCode() * prime;
			}
			res ^= _attempts * prime;
			res ^= _expirations * prime;
			res ^= _evictions * prime;
			res ^= _hits * prime;
			res ^= _removes * prime;
			res ^= _writes * prime;
			return res;
		}

		/// <summary>
		///   Determins if equal to another instance.
		/// </summary>
		/// <param name="other"></param>
		/// <returns></returns>
		public bool Equals(CacheStats other)
		{
			return String.Equals(_name, other._name)
				&& _attempts == other._attempts
				&& _expirations == other._expirations
				&& _evictions == other._evictions
				&& _hits == other._hits
				&& _removes == other._removes
				&& _writes == other._writes
				;
		}
	}
}